/**
 * 配置解析c++库, 实现时调用c库中的parconf, 配置文件样例:
 * 
 * # 这是一个配置文件
 * address = 192.168.1.1
 * port = 10000
 * [database]  # 数据库配置
 *     host = localhost
 *     user = admin
 * 
 * 每行开头以及key,value前后的空白自动过滤,空行过滤 
 * key = value结构, 允许key前后, value前后有空白字符, key串不得有空白
 * 首字母(空白除外)为[表示群组, 用于表示某一类型配置, []内所有字符为群组名称,不建议群组名称有空白
 * 首字母(空白除外)为#表示行注释, key,value以及群组后允许注释, 但必须与群组]或value间隔至少一个空白
 * 
 * 开发者   : Marco
 * 创建时间 : 2016年5月25日, 上午10:50
 */

#ifndef __MARCOPP_PARCONF_H__
#define __MARCOPP_PARCONF_H__

#include "marcopp.h"

typedef struct _IO_FILE FILE;

MARCOPP_NAMESPACE_BEGIN

class parconf_impl;
class pargrp_impl;
class parconf;

/**
 * 群组操作类
 */
class pargrp {
public:
    /**
     * 构造, 配置中无此群组则抛出异常
     * @param conf 配置类, 必须已解析成功, 否则抛出异常
     * @param group_name 群组名称, 允许NULL, 取无名群组
     */
    explicit pargrp(parconf& conf, const char* group_name) throw(int);
    explicit pargrp(const pargrp& orig); // 拷贝构造
#if (__cplusplus >= 201103L)
    pargrp(pargrp&& orig); // 移动构造
    pargrp& operator= (pargrp&& orig) = delete; // 移动赋值运算符重载禁用
#endif
    ~pargrp(void);

    /**
     * 获取名称
     * @return 名称或NULL无名
     */
    const char* get_name(void) const;

    /**
     * 更名, 不能与其它群组重名, 允许设置为无名群组, 但只能有一个无名群组.
     * @param group 群组节点
     * @param new_name 新名称, 置为NULL表示设为无名
     * @return 操作结果
     */
    bool rename(const char* name);

    /**
     * 查找指定key的值
     * @param key 键名
     * @return 成功:值首地址, 失败:NULL
     */
    const char* find(const char* key) const;
    
    /**
     * 运算符重载, 根据key查找value
     * @param key @param key 键名,传入NULL时,则必定返回NULL
     * @return 键值或NULL
     */
    const char* operator[] (const char* key) const;
    const char* operator() (const char* key) const;

    /**
     * 更新指定key名, 未找到原key时或新key有重名返回失败
     * @param key 原键名, 必须非NULL
     * @param new_key 新的键名, 必须非NULL
     * @return 操作结果
     */
    bool rename_key(const char* old_key, const char* new_key);

    /**
     * 更新指定key的value
     * @param key 键, 必须非NULL
     * @param new_value 新值, 必须非NULL
     * @param add 未找到key时是否自动添加
     * @return 操作结果
     */
    bool update_value(const char* key, const char* value, bool add = false);

    /**
     * 添加一条记录(键值对)
     * @param key 键名
     * @param value 值
     * @param update 找到重名key时是否更新原值, true(重名key则更新其值并返回成功), false(重名key返回失败)
     * @return 操作结果
     */
    bool add(const char* key, const char* value, bool update = false);

    /**
     * 删除指定key的记录(键值对)
     * @param key 键
     * @return 操作结果
     */
    bool del(const char* key);
    
private:
    pargrp& operator= (const pargrp& orig) { return *this; } // 拷贝赋值运算符重载禁用
    
    pargrp_impl* impl;
};

/**
 * 配置操作类
 */
class parconf {
public:
    /**
     * 默认构造,不会抛出异常
     */
    explicit parconf(void) throw();
    /**
     * 构造并解析指定的文件,如果解析失败(文件不存在或格式错误),则抛出异常1
     * @param filename 路径文件名
     */
    explicit parconf(const char* filename) throw (int);
    ~parconf(void);
    
    /**
     * 是否已解析有效的配置
     * @return 有效true, 无效false
     */
    bool valid(void) const;

    /**
     * 解析文件,如果之前解析过,则释放之前的信息,重新解析
     * @param filename 路径文件名
     * @return true或false
     */
    bool parse(const char* filename) throw ();

    /**
     * 根据key查找value
     * @param key 键名,传入NULL时,则必定返回NULL
     * @return 键值或NULL
     */
    const char* find(const char* key) const throw ();
    
    /**
     * 在指定的群组中,根据key查找value
     * @param group_name 群组名称,传入NULL时,则必定返回NULL
     * @param key 键名,传入NULL时,则必定返回NULL
     * @return 键值或NULL
     */
    const char* find(const char* group_name, const char* key) const throw ();
    
    /**
     * 运算符重载, 根据key查找value
     * @param key @param key 键名,传入NULL时,则必定返回NULL
     * @return 键值或NULL
     */
    const char* operator[] (const char* key) const;
    const char* operator() (const char* key) const;

    /**
     * ()运算符重载, 在指定群组中, 根据key查找value
     * @param group_name 群组名称
     * @param key 键名
     * @return 键值或NULL
     */
    const char* operator() (const char* group_name, const char* key) const;

    /**
     * 添加群组, 允许添加无名群组, 不能重名.
     * @param group_name 群组名称, 置为NULL则表示添加的是无名群组
     * @return 添加结果
     */
    bool add_group(const char* group_name);
    
    /**
     * 删除群组
     * @param group_name 群组名称
     * @return 删除结果
     */
    bool del_group(const char* group_name);
    
    /**
     * 删除
     * @param group 群组类, 删除后群组类不得使用除析构外的其余方法.
     * @return 删除结果
     */
    bool del_group(const pargrp& group);
    
    /**
     * 重命名群组名
     * @param group_name 群组名
     * @param new_name 新名称
     * @return 操作结果
     */
    bool rename_group(const char* group_name, const char* new_name);
    
    /**
     * 获取群组, 无此群组必定抛出异常
     * @param group_name 群组名称
     * @return 群组类
     */
    pargrp get_group(const char* group_name) throw (int);
    
    /**
     * 添加记录
     * @param group_name 群组名
     * @param key 键
     * @param value 值
     * @param update 已找到此键时, 是否自动更新其值, true(找到此键更新值并返回成功), false(找到返回失败)
     * @return 操作结果
     */
    bool add_key(const char* group_name, const char* key, const char* value, bool update = false);
    
    /**
     * 删除记录
     * @param group_name 群组名称
     * @param key 键
     * @return 操作结果
     */
    bool del_key(const char* group_name, const char* key);
    
    /**
     * 重命名键
     * @param group_name 群组名
     * @param old_key 旧键名
     * @param new_key 新键名
     * @return 操作结果
     */
    bool rename_key(const char* group_name, const char* old_key, const char* new_key);
    
    /**
     * 更新值
     * @param group_name 群组名
     * @param key 键
     * @param value 新值
     * @param add 未找到键时, 是否自动添加此键, true(自动添加新返回成功), false(未找到键返回失败)
     * @return 操作结果
     */
    bool update_value(const char* group_name, const char* key, const char* value, bool add = false);
    
    /**
     * 输出到流
     * @param fp 流指针, 需要调用处打开与关闭
     * @param pertty 是否漂亮的格式
     */
    void output(FILE* fp, bool pertty = true);
    
    /**
     * 输出到指定的文件 
     * @param filename 文件路径
     * @param pertty 是否漂亮的格式
     */
    bool output(const char* filename, bool pertty = true);
    
    friend class pargrp;
private:
    parconf(const parconf& orig) { } // 拷贝构造禁用
    parconf& operator= (const parconf& orig) { return *this; }	// 拷贝赋值运算符重载禁用
    
#if (__cplusplus >= 201103L)
    parconf(parconf&& orig) = delete;		    // 移动构造禁用
    parconf& operator= (parconf&& orig) = delete;   // 移动赋值运算符重载禁用
#endif
    
    parconf_impl* impl;
};

MARCOPP_NAMESPACE_END
#endif /* __MARCOPP_PARCONF_H__ */

